// ==UserScript==
// @name ChatGPT宽屏模式
// @namespace https://greasyfork.org/
// @version 1.2.1
// @description 将页面宽度展开
// @author Await
// @match https://chat.openai.com/
// @match https://chat.openai.com/c/*
// @match https://chat.openai.com/?*
// @match https://poe.com/
// @match https://poe.com/chat/?*
// @license MIT
// ==/UserScript==
(function () {
"use strict";
const attributeKey = "await-attribute";
const cacheOpenStateKey = "await-cache-open-state";
const cacheCloseStateKey = "await-cache-close-state";
const btnId = "await-btn";
const styleId = "await-max-width";
const btnShowTipId = "await-show-tip";
const cacheKey = "await-cache";
const newMaxWidth = "90rem";
const desiredMinWidth = 1280;
const maxCount = 10;
const targetClassName = ".xl\\:max-w-3xl";
const targetClass = "flex flex-col text-sm dark:bg-gray-800";
const cacheTheme = "theme";
const themeDark = "dark";
const themeLight = "light";
const bodyClass = "antialiased";
const growClass = "grow";
// !(function () {
// try {
// var d = document.documentElement,
// c = d.classList;
// c.remove("light", "dark");
// console.log("system", c);
// var e = localStorage.getItem("theme");
// if ("system" === e || (!e && true)) {
// var t = "(prefers-color-scheme: dark)",
// m = window.matchMedia(t);
// if (m.media !== t || m.matches) {
// console.log("1");
// d.style.colorScheme = "dark";
// c.add("dark");
// } else {
// console.log("2");
// d.style.colorScheme = "light";
// c.add("light");
// }
// } else if (e) {
// console.log("3");
// c.add(e || "");
// }
// if (e === "light" || e === "dark") d.style.colorScheme = e;
// } catch (e) {}
// })();
function setCache(key, value) {
localStorage.setItem(key, value);
}
function getCache(key) {
return localStorage.getItem(key);
}
function getByClass(className) {
const func = function (name) {
return document.getElementsByClassName(name);
};
return gets(func, className);
}
function getQuery(name) {
const func = function (name) {
return document.querySelector(name);
};
return gets(func, name);
}
function getById(id) {
const func = function (id) {
return document.getElementById(id);
};
return gets(func, id);
}
function gets(fun, name, count = 0) {
const btn = fun(name);
if (!btn) {
if (count > maxCount) {
return null; //防止死循环
}
setTimeout(function () {
return gets(fun, name, count + 1);
}, 1000);
}
return btn;
}
function styleCreate() {
const style = document.createElement("style");
style.innerHTML = `
.${styleId} {
max-width: ${newMaxWidth} !important;
}
`;
document.head.appendChild(style);
}
function bodyClassFunc() {
const body = getByClass(bodyClass)[0];
if (!body) {
return;
}
const observer = new MutationObserver((mutationsList, observer) => {
for (const mutation of mutationsList) {
if (
mutation.type === "attributes" &&
mutation.attributeName === "style"
) {
const newStyle = body.getAttribute("style");
if (!newStyle) {
btnClickAdd(true);
btnClick(true);
}
}
}
});
const config = { attributes: true, attributeFilter: ["style"] };
observer.observe(body, config);
}
function btnClickAdd(tt = false) {
//只包含这个growClass的class的元素
const promptTextarea = getQuery(`.${growClass}:not([class*=' '])`);
if (!promptTextarea) {
if (!tt) {
return;
} else {
setTimeout(function () {
btnClickAdd(tt);
}, 1000);
return;
}
}
if (!promptTextarea.hasAttribute(attributeKey)) {
promptTextarea.insertAdjacentHTML(
"afterend",
// `
`
``
);
promptTextarea.insertAdjacentHTML(
"afterend",
// ``
``
);
themeAdd();
btnTextUpdate();
run();
promptTextarea.setAttribute(attributeKey, true);
} else {
if (tt) {
setTimeout(function () {
btnClickAdd(tt);
}, 1000);
}
}
}
function removeStyle(el) {
el.style.transition = "max-width 1s";
setTimeout(function () {
el.style.transition = "";
}, 1000);
el.classList.remove(styleId);
}
function editStyle(el) {
el.style.transition = "max-width 1s";
setTimeout(function () {
el.style.transition = "";
}, 1000);
el.classList.add(styleId);
}
function btnTextUpdate() {
const cache2 = getCache(cacheKey);
const btn = getById(btnId);
btn.innerHTML = "";
if (cache2 === cacheOpenStateKey) {
btn.insertAdjacentHTML(
"afterbegin",
`
还原
`
// `
// 还原
`
// `还原`
// `撑开`
);
} else {
btn.insertAdjacentHTML(
"afterbegin",
`
撑开
`
// `撑开`
);
}
btnTypeEdit(btn);
}
function btnTypeEdit(el) {
if (el && !el.hasAttribute(attributeKey)) {
el.addEventListener("click", function () {
setCache(
cacheKey,
getCache(cacheKey) === cacheOpenStateKey
? cacheCloseStateKey
: cacheOpenStateKey
);
run();
btnTextUpdate();
});
el.setAttribute(attributeKey, true);
}
}
function themeAdd() {
const cache = getCache(cacheTheme);
const el = getById(btnId + "-" + cacheTheme);
el.innerHTML = "";
if (cache !== themeLight) {
el.insertAdjacentHTML(
"afterbegin",
`🌞
`
// `🌞
`
);
} else {
el.insertAdjacentHTML(
"afterbegin",
`🌙
`
);
}
textInformation(el);
textInformation(
getById(btnId + "-" + cache === themeDark ? themeDark : themeLight)
);
}
function textInformation(el) {
if (el && !el.hasAttribute(attributeKey)) {
el.addEventListener("click", function () {
const cache = getCache(cacheTheme);
//修改html中的style跟class
const html = getQuery("html");
const currentTheme = cache !== themeLight ? themeLight : themeDark;
html.className = "";
html.className = currentTheme;
html.style.colorScheme = currentTheme;
setCache(cacheTheme, currentTheme);
themeAdd();
});
el.setAttribute(attributeKey, true);
}
}
function checkCache() {
const cache = getCache(cacheKey);
if (!cache) {
setCache(cacheKey, true);
}
}
function setStyle(cache, el) {
if (cache === cacheOpenStateKey) {
editStyle(el);
} else {
removeStyle(el);
}
}
function getNav(count = 0) {
const nav = document.querySelector("nav");
if (!nav) {
if (count > maxCount) {
return null;
}
setTimeout(function () {
return getNav(count);
}, 1000);
}
return nav;
}
function showTip() {
const toggleButton = getNav();
if (!toggleButton) {
return;
}
toggleButton.insertAdjacentHTML(
"beforeend",
`如果页面宽度未展开,请重新点击此树结构导航栏
或者直接点击我
提示内容十秒后自动消失
`
);
const btn = getById(btnShowTipId);
if (!btn.hasAttribute(attributeKey)) {
btn.addEventListener("click", function () {
runAll();
});
setTimeout(function () {
btn.remove();
}, 10000);
btn.setAttribute(attributeKey, true);
}
}
function btnClick(tt = false) {
const toggleButton = getNav();
if (!toggleButton) {
if (!tt) return;
else {
setTimeout(function () {
btnClick(tt);
}, 1000);
return;
}
}
if (!toggleButton.hasAttribute(attributeKey)) {
toggleButton.addEventListener("click", function () {
setTimeout(function () {
runAll();
btnClick();
}, 1000);
});
toggleButton.setAttribute(attributeKey, true);
} else {
if (tt) {
setTimeout(function () {
btnClick(tt);
}, 1000);
}
}
}
function checkForm() {
var elementForm = document.querySelectorAll("form");
if (!elementForm || elementForm.length === 0) {
setTimeout(function () {
checkObserver();
}, 1000);
return;
}
const cache = getCache(cacheKey);
elementForm.forEach(function (element) {
if (element.className.indexOf("xl:max-w-3xl") > -1) {
setStyle(cache, element);
}
});
}
function checkObserver() {
var parentElement = document.getElementsByClassName(targetClass)[0];
if (!parentElement) {
setTimeout(function () {
checkObserver();
}, 1000);
return;
}
const cache = getCache(cacheKey);
parentElement.querySelectorAll(targetClassName).forEach(function (flexDiv) {
setStyle(cache, flexDiv);
});
var observer = new MutationObserver((mutations) => {
mutations.forEach(function (mutation) {
if (!document.contains(parentElement)) {
observer.disconnect();
return;
}
mutation.addedNodes.forEach(function (addedNode) {
if (addedNode instanceof Document || addedNode instanceof Element) {
var flexDivList = addedNode.querySelectorAll(targetClassName);
flexDivList.forEach(function (flexDiv) {
setStyle(cache, flexDiv);
});
}
});
});
});
var config = { childList: true, subtree: true };
observer.observe(document.body, config);
}
function runAll() {
btnClickAdd();
themeAdd();
}
function run() {
checkForm();
checkObserver();
}
window.addEventListener("resize", runAll);
window.onload = function () {
if (window.innerWidth < desiredMinWidth) {
return;
}
checkCache();
bodyClassFunc();
styleCreate();
showTip();
btnClick();
setTimeout(function () {
runAll();
}, 2000);
};
})();